home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
TeX 1995 July
/
TeX CD-ROM July 1995 (Disc 1)(Walnut Creek)(1995).ISO
/
dviware
/
dvi2qms
/
qmsfonts.c
< prev
next >
Wrap
C/C++ Source or Header
|
1990-10-01
|
17KB
|
615 lines
/* qmsfonts.c: font module for dvi printing on qms printers
* Copyright 1985 Massachusetts Institute of Technology
* Some portions were written by Scott Simpson, TRW
*/
#include <stdio.h>
#include <sys/types.h>
#include <sys/dir.h>
#include "util.h"
#include "fonts.h"
#include "findfile.h"
#define MAXDVIFONTS 256 /* Maximum number of DVI fonts allowed */
#define MAXQMSFONTS 256 /* Maximum number of QMS fonts allowed */
#define QMSMAXBLOCKS 386 /* Stated on qms status page */
#define MAXCHARS 128 /* Max chars per QMS font */
#define MAXFNTDIR 16 /* Max number of dirs to look for fonts */
#define MAXFNTNAMLEN 32 /* Maximum number of chars in a font name */
#define USEROTPXL 1 /* Write and read rotated pxl files */
#define DELETEFONT "^DF%05.5d%c^G"
#define DEFINEFONT "^(^DF%05.5d%c%c%4.4s%03.3dT"
#define ADDTOFONT "^(^DFI%05.5d%c%c%4.4s%03.3dT"
#define DEFINECHAR ",%c%c%03.3d%03.3d%03.3d%c%03.3d%c%03.3d"
#define ENDDEF "^G^)"
#define SELECTFONT "^IS%05.5d"
unsigned char *malloc();
char *strcat();
char *strcpy();
char *strncpy();
char *strncmp();
char *strcmp();
long numerator,denominator,half_denominator,jobmag;
char job_orientation,printer_orientation;
int freeblocks = QMSMAXBLOCKS; /* free space on printer */
char *hex = "0123456789ABCDEF";
FILE *qms; /* output device */
char *filter_name; /* the name of the calling prog */
char *fntdirvec[MAXFNTDIR];
int fntdirveclen;
#define QC_LOADED 0x0001 /* Char has been loaded in the printer */
#define QC_NOGLYPH 0x0002 /* Glyph is still in pxl file */
#define QC_ROTATED 0x0004 /* Glyph has been rotated */
#define QC_NEEDED 0x0008 /* This char is needed on this page */
struct qmschar {
short qc_info,qc_qmswidth;
short qc_height,qc_width;
short qc_xoffset,qc_yoffset;
long qc_texwidth,qc_pxlwidth;
union {long l; unsigned char *p} qc_glyph;
};
#define QF_LOADED 0x0001 /* Font has been loaded into printer */
#define QF_RELOAD 0x0002 /* We have to load more needed chars */
#define QF_FILE 0x0004 /* Font hasn't been loaded from the file */
struct qmsfont {
short qf_info;
short qf_qmsnumber;
short qf_maxheight;
long qf_mag;
long qf_words_used;
long qf_words_needed;
long qf_timestamp;
char qf_qmsname[4];
long qf_pxl_checksum;
long qf_pxl_mag_val;
long qf_pxl_design_size;
long qf_s;
char qf_name[MAXFNTNAMLEN];
char qf_filename[MAXNAMLEN];
struct qmschar qf_char[MAXCHARS];
} *qmsfonts[MAXQMSFONTS];
int nqmsfonts;
struct qmsfont *curfnt; /* ptr to current and last font */
long timestamp; /* Timestamp for stamping qms fonts */
/* The dvifont struct provides a (possible) many-to-one mapping
* because several DVI fonts can map to the same QMS font during font
* substitution.
*/
struct dvifont {
unsigned long df_num; /* DVI font number */
struct qmsfont *df_qmsfont; /* Font which contains */
} dvifonts[MAXDVIFONTS];
int ndvifonts;
long max(a,b)
long a,b;
{
return((a>b)? a:b);
}
long min(a,b)
long a,b;
{
return((a<b)? a:b);
}
/* called at the beginning of the driver program */
f_init(printer,pgmnam,dirvec,dirveclen,num,den,mag,options)
FILE *printer;
char *pgmnam,*dirvec[];
int dirveclen;
long num,den,mag;
unsigned long options;
{
int i;
numerator = num;
denominator = den;
half_denominator = denominator / 2;
jobmag = mag;
fntdirveclen = min(MAXFNTDIR,dirveclen);
for (i = 0; i < fntdirveclen; i++) fntdirvec[i] = dirvec[i];
ndvifonts = 0;
nqmsfonts = 0;
timestamp = 0;
qms = printer;
filter_name = pgmnam;
if (options & F_INIT_LANDSCAPE) job_orientation = 'L';
else job_orientation = 'P';
if (options & F_INIT_QMS800) printer_orientation = 'P';
else printer_orientation = 'L';
}
/* Called at the end of the driver program. */
f_term()
{
}
struct qmsfont *
find_qmsfont(area,name,texmag,s)
char *area,*name;
long texmag,s;
{
char fname[MAXNAMLEN],nname[128];
int i,nmag;
int mag = (texmag * 3 + 1) / 2;
struct qmsfont *fnt;
/* try to find a font file */
if (!findfile(fntdirvec,fntdirveclen,area,name,mag,fname,nname,&nmag))
croak("no font %s.%d",name,texmag);
/* make a new qms font */
if (nqmsfonts >= MAXQMSFONTS) croak("too many qms fonts");
if (!(qmsfonts[nqmsfonts++] = fnt =
(struct qmsfont *) malloc(sizeof(struct qmsfont))))
croak("malloc %d",sizeof(struct qmsfont));
fnt->qf_mag = nmag;
fnt->qf_timestamp = 0;
fnt->qf_words_needed = 400;
fnt->qf_words_used = 0;
fnt->qf_qmsnumber = nqmsfonts + 1000;
sprintf(fnt->qf_qmsname,"%04.4d",fnt->qf_qmsnumber);
fnt->qf_maxheight = 0;
fnt->qf_s = s;
strcpy(fnt->qf_name,nname);
strcpy(fnt->qf_filename,fname);
fnt->qf_info = QF_FILE;
return(fnt);
}
getfontfromfile(fnt)
struct qmsfont *fnt;
{
char fname[MAXNAMLEN];
FILE *f;
int i;
sprintf(fname,"%sr",fnt->qf_filename);
if (USEROTPXL && job_orientation != printer_orientation) {
if (!access(fname,4)) readpxlfile(fnt,fname,1);
else {
readpxlfile(fnt,fnt->qf_filename,0);
if (f = fopen(fname,"w")) {
fclose(f);
for (i = 0; i < MAXCHARS; i++) rotate(&(fnt->qf_char[i]),fnt);
writepxlfile(fnt,fname);
}
}
} else readpxlfile(fnt,fnt->qf_filename,0);
fnt->qf_info &= ~QF_FILE;
}
writepxlfile(fnt,fname)
struct qmsfont *fnt;
char *fname;
{
FILE *f;
long glyphaddrs[MAXCHARS],pxl_dir_ptr;
if (!(f = fopen(fname,"w"))) croak("can't open %s to write",fname);
put4(1001,f);
writeglyphs(fnt,f,glyphaddrs);
pxl_dir_ptr = ftell(f) / 4;
writepxldir(fnt,f,glyphaddrs);
put4(fnt->qf_pxl_checksum,f);
put4(fnt->qf_pxl_mag_val,f);
put4(fnt->qf_pxl_design_size,f);
put4(pxl_dir_ptr,f);
put4(1001,f);
fclose(f);
}
writepxldir(fnt,f,glyphaddrs)
struct qmsfont *fnt;
FILE *f;
long glyphaddrs[];
{
int i;
struct qmschar *c;
for (i = 0; i < MAXCHARS; i++) {
c = &(fnt->qf_char[i]);
put2(c->qc_width,f);
put2(c->qc_height,f);
put2(c->qc_xoffset,f);
put2(c->qc_yoffset,f);
put4(glyphaddrs[i],f);
put4(c->qc_pxlwidth,f);
}
}
writeglyphs(fnt,f,glyphaddrs)
struct qmsfont *fnt;
FILE *f;
long glyphaddrs[];
{
register int j;
int i,fbw,bw,row;
struct qmschar *c;
register unsigned char *p;
for (i = 0; i < MAXCHARS; i++) {
c = &(fnt->qf_char[i]);
if (c->qc_glyph.p) {
glyphaddrs[i] = ftell(f) / 4;
/* Write out this glyph to the PXL file */
p = c->qc_glyph.p;
bw = (c->qc_width + 7) / 8;
fbw = ((c->qc_width + 31) / 32) * 4;
for (row = 0; row < c->qc_height; row++) {
for (j = 0; j < bw; j++) putc(*p++,f);
for (j = bw; j < fbw; j++) putc(0,f);
}
} else glyphaddrs[i] = 0;
}
}
int char_words_needed(c)
struct qmschar *c;
{
if (c->qc_info & QC_ROTATED)
return(((c->qc_width + 15) / 16) * c->qc_height);
else
return(((c->qc_height + 15) / 16) * c->qc_width);
}
int font_blocks_used(fnt)
struct qmsfont *fnt;
{
return((fnt->qf_words_used + 511) / 512);
}
int font_blocks_needed(fnt)
struct qmsfont *fnt;
{
return((fnt->qf_words_needed + fnt->qf_words_used + 511) / 512
- font_blocks_used(fnt));
}
/* Define a font.
* Can be called more than once for the same font.
*/
f_define_font(num,options,area,name,texmag,s,tfmchecksum)
char *area,*name;
unsigned long num,options,texmag,s,tfmchecksum;
{
int i;
/* check to see if font is already defined */
for(i = 0; i < ndvifonts ; i++) if (dvifonts[i].df_num == num) return;
/* Does this make too many fonts defined? */
if (ndvifonts >= MAXDVIFONTS) croak("too many dvi fonts");
dvifonts[ndvifonts].df_num = num;
dvifonts[ndvifonts++].df_qmsfont = find_qmsfont(area,name,texmag,s);
}
struct qmsfont *
find_dvi_font(fontnum)
unsigned long fontnum;
{
register int i;
/* scan through the dvi font list. */
for(i = 0; i < ndvifonts ; i++)
if (dvifonts[i].df_num == fontnum) {
dvifonts[i].df_qmsfont->qf_timestamp = timestamp++;
return(dvifonts[i].df_qmsfont);
}
croak("no dvi font %d defined",fontnum);
}
/* Set a font as the current font.
*/
f_use_font(fontnum,font_space)
unsigned long fontnum;
long *font_space;
{
curfnt = find_dvi_font(fontnum);
if (curfnt->qf_info & QF_FILE) getfontfromfile(curfnt);
/* Make sure that it's loaded in the printer */
if (!(curfnt->qf_info & QF_LOADED)
|| (curfnt->qf_info & QF_RELOAD))
download_font(curfnt);
/* Start using it */
fprintf(qms,SELECTFONT,curfnt->qf_qmsnumber);
*font_space = curfnt->qf_s / 6;
}
/* Hints as to what fonts are to be used.
* This is called once per page to give fonts module hints as what fonts
* and characters in those fonts are going to be used on this page.
*/
f_newpage(fontvec,charvec,veclen)
unsigned long fontvec[];
unsigned long charvec[][4];
int veclen;
{
struct qmschar *c;
register int i,j;
struct qmsfont *f;
for (i = 0; i < veclen; i++) {
f = find_dvi_font(fontvec[i]);
if (f->qf_info & QF_FILE) getfontfromfile(f);
if (!(f->qf_info & QF_LOADED)) {
f->qf_words_used = 0;
f->qf_words_needed = 400;
}
for (j = 0; j < MAXCHARS; j++)
if (charvec[i][j/32] & (1 << (j % 32))) {
c = &(f->qf_char[j]);
c->qc_info |= QC_NEEDED;
if (!(c->qc_info & QC_LOADED)) {
f->qf_info |= QF_RELOAD;
f->qf_words_needed += char_words_needed(c);
}
} else f->qf_char[j].qc_info &= ~QC_NEEDED;
}
}
clear(p,n)
char *p;
int n;
{
while (n-- > 0) *p++ = 0;
}
rotate(c,fnt)
struct qmschar *c;
struct qmsfont *fnt;
{
unsigned char *oldglyph = c->qc_glyph.p;
unsigned int width = (unsigned int)c->qc_width;
unsigned int height = (unsigned int)c->qc_height;
int newbyteswide = (c->qc_height + 7) / 8;
int oldbyteswide = (c->qc_width + 7) / 8;
unsigned char *newglyph,*putbyte;
int column;
int row = -1; /* Start row at 0 when incremented */
int mask;
int i, j;
int times;
int extractbyte;
if (!(c->qc_info & QC_NOGLYPH)) {
if (!(newglyph = malloc(newbyteswide * width)))
croak("malloc %d",newbyteswide * width);
clear(newglyph, newbyteswide * width);
for (i = 0; i < oldbyteswide * height; i++) {
extractbyte = *(oldglyph + i);
if (i % oldbyteswide == 0) row++;
times = (i + 1) % oldbyteswide ? 8 : (width + 7) % 8 + 1;
for (j = 0, mask = 0x80; j < times; j++, mask >>= 1) {
column = (((i % oldbyteswide) == 0) && (j == 0)) ? 0 : (column + 1);
if (mask & extractbyte) {
putbyte = newglyph + column * newbyteswide +
(int)((height - (row + 1)) / 8);
*putbyte |= 1 << 7 - ((height + 7) - row) % 8;
}
}
}
free(oldglyph);
c->qc_glyph.p = newglyph;
}
c->qc_info |= QC_ROTATED;
i = c->qc_width;
c->qc_width = c->qc_height;
c->qc_height = i;
i = c->qc_xoffset;
c->qc_xoffset = c->qc_width - c->qc_yoffset - fnt->qf_maxheight;
c->qc_yoffset = i;
}
/* Load a font into the qms.
*/
download_font(fnt)
struct qmsfont *fnt;
{
register int i;
if (font_blocks_needed(fnt) > freeblocks)
qmsfree(font_blocks_needed(fnt));
freeblocks -= font_blocks_needed(fnt);
fnt->qf_words_used += fnt->qf_words_needed;
fnt->qf_words_needed = 0;
if (fnt->qf_info & QF_LOADED) {
fprintf(qms,
ADDTOFONT,
fnt->qf_qmsnumber,job_orientation,
1,fnt->qf_qmsname,fnt->qf_maxheight);
} else {
fprintf(qms,
DEFINEFONT,
fnt->qf_qmsnumber,job_orientation,
1,fnt->qf_qmsname,fnt->qf_maxheight);
}
for (i = 0; i < MAXCHARS; i++)
if ((fnt->qf_char[i].qc_info & QC_NEEDED)
&& !(fnt->qf_char[i].qc_info & QC_LOADED))
load_char(i,fnt);
fprintf(qms,ENDDEF);
fnt->qf_info |= QF_LOADED;
fnt->qf_info &= ~QF_RELOAD;
}
load_char(ch,fnt)
unsigned long ch;
struct qmsfont *fnt;
{
register unsigned char *bp;
register int bytes;
struct qmschar *c = &(fnt->qf_char[ch]);
int row,bw,bo;
if (job_orientation != printer_orientation
&& !(c->qc_info & QC_ROTATED)) rotate(c,fnt);
bp = c->qc_glyph.p;
fprintf(qms,DEFINECHAR,hex[(ch >> 4) & 017],hex[ch & 017],
c->qc_qmswidth,c->qc_height,c->qc_width,
(c->qc_yoffset < 0) ? '+' : '-',abs(c->qc_yoffset),
(c->qc_xoffset < 0) ? '+' : '-',abs(c->qc_xoffset));
bw = (c->qc_width + 7) / 8;
bo = ((c->qc_width + 15) / 16) * 2;
for (row = 0; row < c->qc_height; row++) {
for (bytes = 0; bytes < bw; bytes++) putc(*bp++,qms);
if (bw != bo) putc(0,qms);
}
c->qc_info |= QC_LOADED;
}
int readpxlfile(fnt,fname,rotated)
struct qmsfont *fnt;
char *fname;
int rotated;
{
long pxl_id,pxl_dir_ptr;
FILE *f;
if (!(f = fopen(fname,"r"))) croak("no pxl file %s",fname);
if ((pxl_id = sget4(f)) != 1001)
croak("%d bad initial pxl ID; %s doesn't look like a pxl file",
pxl_id, fnt->qf_filename);
/* Read the last 5 longs from the pxl file */
(void) fseek(f, (long)(-5*4), 2);
fnt->qf_pxl_checksum = sget4(f);
fnt->qf_pxl_mag_val = sget4(f);
fnt->qf_pxl_design_size = sget4(f);
pxl_dir_ptr = sget4(f);
if ((pxl_id = sget4(f)) != 1001)
croak("%d bad final pxl ID; %s doesn't look like a pxl file",
pxl_id, fnt->qf_filename);
if (pxl_dir_ptr != ftell(f) / 4 - 517)
croak("%s pxl dir ptr is %x, should be %x",
fnt->qf_filename, pxl_dir_ptr, ftell(f) / 4 - 517);
debug("pxl: checksum %d mag %d designsize %d dir %x\n",
fnt->qf_pxl_checksum,fnt->qf_pxl_mag_val,
fnt->qf_pxl_design_size,pxl_dir_ptr);
/* Read the directory */
(void) fseek(f, pxl_dir_ptr * 4, 0);
getpxldir(fnt,f,rotated);
debug(" %s max_height=%d\n",fnt->qf_filename,fnt->qf_maxheight);
/* Read in all the glyphs */
getglyphs(fnt,f);
(void) fclose(f);
}
getpxldir(fnt,f,rotated)
struct qmsfont *fnt;
FILE *f;
int rotated;
{
int i;
struct qmschar *c;
double ds = ((double) fnt->qf_s) / ((double) (1 << 20));
fnt->qf_maxheight = 0;
for (i = 0; i < MAXCHARS; i++) {
c = &(fnt->qf_char[i]);
c->qc_width = sget2(f);
c->qc_height = sget2(f);
c->qc_xoffset = sget2(f);
c->qc_yoffset = sget2(f);
c->qc_glyph.l = get4(f);
c->qc_pxlwidth = sget4(f);
c->qc_texwidth = (long) (((double) c->qc_pxlwidth) * ds);
c->qc_qmswidth =
(c->qc_texwidth * numerator + half_denominator) / denominator;
if (rotated) {
c->qc_info = QC_NOGLYPH | QC_ROTATED;
fnt->qf_maxheight = max(fnt->qf_maxheight,c->qc_width);
} else {
c->qc_info = QC_NOGLYPH;
fnt->qf_maxheight = max(fnt->qf_maxheight,c->qc_height);
}
}
}
getglyphs(fnt,f)
struct qmsfont *fnt;
FILE *f;
{
register int j,row;
register unsigned char *p;
int i,fbw,bw;
struct qmschar *c;
for (i = 0; i < MAXCHARS; i++) {
c = &(fnt->qf_char[i]);
if (c->qc_glyph.l) {
(void) fseek(f, c->qc_glyph.l * 4, 0);
fbw = ((c->qc_width + 31) / 32) * 4;
bw = (c->qc_width + 7) / 8;
if (!(p = malloc(bw * c->qc_height)))
croak("malloc %d",bw * c->qc_height);
c->qc_glyph.p = p;
for (row = 0; row < c->qc_height; row++) {
for (j = 0; j < bw; j++) *p++ = getc(f);
for (j = bw; j < fbw; j++) (void) getc(f);
}
c->qc_info &= ~QC_NOGLYPH;
}
}
}
/* Make sure that the font info for this character is loaded.
* Characters are incrementally loaded into the printer.
* This procedure is called for every character so it must be fast.
*/
f_use_char(ch,texwidth,devwidth)
unsigned long ch;
long *texwidth,*devwidth;
{
register struct qmschar *c = &(curfnt->qf_char[ch]);
*texwidth = c->qc_texwidth;
*devwidth = c->qc_qmswidth;
}
/* free blocks by deleting font(s) using LRU strategy */
int qmsfree(blocks)
int blocks;
{
int i,oldtime;
struct qmsfont *oldfont;
while (blocks > freeblocks) {
oldfont = NULL;
oldtime = timestamp;
for (i = 0; i < nqmsfonts; i++)
if ((qmsfonts[i]->qf_info & QF_LOADED)
&& (qmsfonts[i]->qf_timestamp < oldtime)) {
oldfont = qmsfonts[i];
oldtime = oldfont->qf_timestamp;
}
if (!oldfont) croak("qmsfree bug");
fprintf(qms,DELETEFONT,oldfont->qf_qmsnumber,job_orientation);
freeblocks += font_blocks_used(oldfont);
oldfont->qf_info &= ~QF_LOADED;
oldfont->qf_words_needed = 400;
oldfont->qf_words_used = 0;
for (i = 0; i < MAXCHARS; i++) {
oldfont->qf_char[i].qc_info &= ~QC_LOADED;
if (oldfont->qf_char[i].qc_info & QC_NEEDED)
oldfont->qf_words_needed += char_words_needed(&(oldfont->qf_char[i]));
}
}
}